﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinRTFramework.FrameworkConfiguration;
using WinRTFramework.FrameworkCore;
using WinRTFramework.FrameworkCore.Managers;
using WinRTFramework.FrameworkCore.Services;
using WinRTFramework.Interfaces.AppStates;
using WinRTFramework.Interfaces.Contracts.Search;
using WinRTFramework.Interfaces.Contracts.Sharing;
using WinRTFramework.Interfaces.Navigation;
using WinRTFramework.Interfaces.Navigation.ViewModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using WinRTFramework.Contracts;
using WinRTFramework.Interfaces.Contracts.Settings.ViewModel;
using WinRTFramework.Interfaces.Contracts.Settings;
using WinRTFramework.Interfaces.Dialog;
using WinRTFramework.Interfaces.Dialog.ViewModel;

namespace WinRTFramework
{
    public class WinRTContainer : IServiceInjector
    {
        private readonly IApplicationAdapter applicationAdapter;
        private readonly Frame rootFrame;
        private readonly IIoCAdapter iocAdapter;
        private readonly IViewViewModelMapper viewProvider;
        private readonly SettingsManager settingsManager;
        private readonly SharingSourceManager sharingSourceManager;
        private readonly NavigationManager navigationManager;
        
        public INavigationService NavigationService { get; private set; }
        public ISharingService SharingService { get; private set; }
        public ISettingService SettingService { get; private set; }
        public IDialogService DialogService { get; private set; }

        public WinRTContainer(IApplicationAdapter applicationAdapter, Frame rootFrame, IIoCAdapter iocAdapter, IViewViewModelMapper viewProvider)
        {
            this.applicationAdapter = applicationAdapter;
            this.rootFrame = rootFrame;
            this.iocAdapter = iocAdapter;
            this.viewProvider = viewProvider;
            this.settingsManager = new SettingsManager(iocAdapter, viewProvider, rootFrame);
            this.sharingSourceManager = new SharingSourceManager(rootFrame);
            this.navigationManager = NavigationManager.CreateFrom(applicationAdapter, rootFrame, viewProvider, this, new NavigationManager.NavigationManagerOptions() { HandleResumeAndSuspend = true });

            this.NavigationService = new NavigationService(rootFrame, viewProvider);
            this.SharingService = new SharingService();
            this.SettingService = new SettingService(viewProvider, iocAdapter);
            this.DialogService = new DialogService();

            RegisterTransientStateTypes();
        }

        private void RegisterTransientStateTypes()
        {
            List<Type> transientTypes = new List<Type>();
            foreach(var registeredType in iocAdapter.GetAllRegisteredTypes())
            {
                var instance = iocAdapter.GetInstanceOfType(registeredType);
                if(instance is ISupportTransientState)
                {
                    transientTypes.AddRange(((ISupportTransientState)instance).GetTransientStateTypes());
                }
            }
            SuspensionManager.KnownTypes.AddRange(transientTypes.Distinct());
        }
        
        public void InjectServicesIntoViewModel(object viewModel)
        {
            if(viewModel is IRequireNavigationService)
            {
                ((IRequireNavigationService)viewModel).NavigationService = this.NavigationService;
            }

            if(viewModel is IRequireSharingService)
            {
                ((IRequireSharingService)viewModel).SharingService = this.SharingService;
            }

            if (viewModel is IRequireSettingService)
            {
                ((IRequireSettingService)viewModel).SettingService = this.SettingService;
            }

            if (viewModel is IRequireDialogService)
            {
                ((IRequireDialogService)viewModel).DialogService = this.DialogService;
            }
        }
    }
}
